package com.example.nacos.cal;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.fastjson2.JSON;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class ProductReturnCalculator {
    @Getter
    @Setter
    @EqualsAndHashCode
    public static class ProductData {
        @ExcelProperty("产品编码")
        private String productCode;
        @ExcelProperty("统计日期")
        private LocalDate statisticDate;
        @ExcelProperty("累计净值")
        private double cumulativeNetValue;

    }

    public static class AnnualizedReturnResult {
        private String productCode;
        private Double threeMonthsReturn;
        private Double sixMonthsReturn;
        private Double sinceInceptionReturn;

        public AnnualizedReturnResult(String productCode, Double threeMonthsReturn,
                                      Double sixMonthsReturn, Double sinceInceptionReturn) {
            this.productCode = productCode;
            this.threeMonthsReturn = threeMonthsReturn;
            this.sixMonthsReturn = sixMonthsReturn;
            this.sinceInceptionReturn = sinceInceptionReturn;
        }

        @Override
        public String toString() {
            return String.format("产品编码: %s | 近三个月: %.2f%% | 近半年: %.2f%% | 成立以来: %.2f%%",
                    productCode,
                    threeMonthsReturn != null ? threeMonthsReturn * 100 : Double.NaN,
                    sixMonthsReturn != null ? sixMonthsReturn * 100 : Double.NaN,
                    sinceInceptionReturn != null ? sinceInceptionReturn * 100 : Double.NaN);
        }
    }

    public static AnnualizedReturnResult calculateAnnualizedReturn(List<ProductData> group) {
        if (group == null || group.isEmpty()) {
            return new AnnualizedReturnResult("", null, null, null);
        }

        // 按日期排序
        List<ProductData> sortedGroup = group.stream()
                .sorted(Comparator.comparing(ProductData::getStatisticDate))
                .collect(Collectors.toList());

        String productCode = sortedGroup.get(0).getProductCode();
        double endValue = sortedGroup.get(sortedGroup.size() - 1).getCumulativeNetValue();
        LocalDate maxDate = sortedGroup.stream()
                .map(ProductData::getStatisticDate)
                .max(LocalDate::compareTo)
                .orElse(LocalDate.now());

        // 近三个月年化收益率
        LocalDate threeMonthsCutoff = maxDate.minusMonths(3);
        List<ProductData> threeMonthsData = sortedGroup.stream()
                .filter(data -> !data.getStatisticDate().isBefore(threeMonthsCutoff))
                .collect(Collectors.toList());

        Double annualizedReturnThreeMonths = calculateReturnForPeriod(threeMonthsData, endValue);

        // 近半年年化收益率
        LocalDate sixMonthsCutoff = maxDate.minusMonths(6);
        List<ProductData> sixMonthsData = sortedGroup.stream()
                .filter(data -> !data.getStatisticDate().isBefore(sixMonthsCutoff))
                .collect(Collectors.toList());

        Double annualizedReturnSixMonths = calculateReturnForPeriod(sixMonthsData, endValue);

        // 成立以来年化收益率
        Double annualizedReturnSinceInception = calculateReturnForPeriod(sortedGroup, endValue);

        return new AnnualizedReturnResult(
                productCode,
                annualizedReturnThreeMonths,
                annualizedReturnSixMonths,
                annualizedReturnSinceInception);
    }

    private static Double calculateReturnForPeriod(List<ProductData> dataList, double endValue) {
        if (dataList.size() < 2) {
            return null;
        }

        double startValue = dataList.get(0).getCumulativeNetValue();
        LocalDate startDate = dataList.get(0).getStatisticDate();
        LocalDate endDate = dataList.get(dataList.size() - 1).getStatisticDate();

        long daysDiff = ChronoUnit.DAYS.between(startDate, endDate);
        if (daysDiff <= 0) {
            return null;
        }

        double period = (double) daysDiff / 365;
        return Math.pow(endValue / startValue, 1.0 / period) - 1;
    }

    public static Map<String, List<ProductData>> groupByProductCode(List<ProductData> allData) {
        return allData.stream()
                .collect(Collectors.groupingBy(ProductData::getProductCode));
    }

    public static List<AnnualizedReturnResult> calculateAllProductsReturns(List<ProductData> allData) {
        Map<String, List<ProductData>> groupedData = groupByProductCode(allData);
        List<AnnualizedReturnResult> results = new ArrayList<>();

        for (Map.Entry<String, List<ProductData>> entry : groupedData.entrySet()) {
            AnnualizedReturnResult result = calculateAnnualizedReturn(entry.getValue());
            results.add(result);
        }

        return results;
    }

    public static void main(String[] args) {
        // 和单位净值没有关系 只与累计净值有关
        String fileName =  "D:\\python\\ind_cal\\净值数据.xlsx";
        // 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
        // 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行
        // 具体需要返回多少行可以在`PageReadListener`的构造函数设置
        List<ProductData> sampleData = new ArrayList<>();

        EasyExcel.read(fileName, ProductData.class, new PageReadListener<ProductData>(sampleData::addAll)).sheet().doRead();
        if(sampleData.isEmpty()){
            System.out.println("没有数据");
            return;
        }
        log.info("一条为：{}", JSON.toJSONString(sampleData.get(0)));
        log.info("数据总数为：{}", sampleData.size());
        System.out.println("金融产品年化收益率计算结果:");
        System.out.println("=" .repeat(80));



        List<AnnualizedReturnResult> results = calculateAllProductsReturns(sampleData);

        for (AnnualizedReturnResult result : results) {
            System.out.println(result);
        }

        log.info("=" .repeat(80));
        log.info("计算完成，共处理 " + results.size() + " 个产品");
    }
}
